package priv.conceit.study.leetcode.medium;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

/**
 * 编号：1115
 * 交替打印FooBar
 *
 * @description: <a href="https://leetcode-cn.com/problems/print-foobar-alternately/">
 * @return:
 * @author: conceit
 * @date: 2019/11/1 15:00
 */
public class PrintFoobarAlternately {
	private int n;
	CyclicBarrier barrier;
	CountDownLatch countDownLatch;

	/**
	 * 实现线程交替打印
	 * 使用循环格栅，
	 * foo线程优先执行，执行完毕进行等待，bar线程先进行等待，在执行。
	 * 当两个个线程都执行完毕，则继续循环操作
	 *
	 * 两个线程 每次循环的优先级 依赖CountDownLatch执行
	 *
	 * 本地测试可以通过，leetcode超时
	 *
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {
		PrintFoobarAlternately printFoobarAlternately = new PrintFoobarAlternately(50);
		new Thread(() -> {
			try {
				printFoobarAlternately.foo(() -> System.out.println("foo"));
			} catch (InterruptedException | BrokenBarrierException e) {
				e.printStackTrace();
			}
		}).start();
		new Thread(() -> {
			try {
				printFoobarAlternately.bar(() -> System.out.println("bar"));
			} catch (InterruptedException | BrokenBarrierException e) {
				e.printStackTrace();
			}
		}).start();

	}

	public PrintFoobarAlternately(int n) {
		this.n = n;
		barrier = new CyclicBarrier(2);
		countDownLatch=new CountDownLatch(1);
	}

	public void foo(Runnable printFoo) throws InterruptedException, BrokenBarrierException {

		for (int i = 0; i < n; i++) {
			printFoo.run();
			countDownLatch.countDown();
			barrier.await();
			// printFoo.run() outputs "foo". Do not change or remove this line.
		}
	}

	public void bar(Runnable printBar) throws BrokenBarrierException, InterruptedException {

		for (int i = 0; i < n; i++) {
			countDownLatch.await();
			barrier.await();
			printBar.run();
			countDownLatch=new CountDownLatch(1);
			// printBar.run() outputs "bar". Do not change or remove this line.
		}
	}
}
